package fem2;

import inf.jlinalg.SolveFailedException;
import inf.text.ArrayFormat;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import junit.framework.Assert;
import math2.FunctionRnToR;
import math2.MathUtilities;
import math2.RampFunctionRToR;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import fem2.analysis.Analysis;
import fem2.analysis.LinearStaticAnalysis;
import fem2.element.NonlinearStructuralElement;

@RunWith(Parameterized.class)
public abstract class AbstractPatchTestNonlinear {

	protected double du;
	protected double[][] Uh;
	private int option;

	@Parameters
	public static Collection<Object[]> parameters() {
		List<Object[]> params = new LinkedList<Object[]>();

		params.add(new Object[] { 0 });
		params.add(new Object[] { 1 });
		return params;
	}

	public AbstractPatchTestNonlinear(int option) {
		this.option = option;
	}

	public abstract MaterialModel createMaterial();

	public Model createModel() {
		Mesh mesh;
		switch (option) {
		case 0:
			mesh = createMeshT3();
			break;
		case 1:
			mesh = createMeshQ4();
			break;
		default:
			throw new Error("invalid option");
		}

		Model M = new Model(mesh);
		MaterialModel mm = createMaterial();

		for (int i = 0; i < mesh.countFaces(); i++) {
			Element e = new NonlinearStructuralElement(mesh.getFace(i), mm);
			M.addElement(e);
		}

		return M;
	}

	@Test
	public void solveAndCheck2() throws SolveFailedException {
		Model m = createModel();
		double F = 1;
		Mesh mesh = m.getMesh();

		FunctionRnToR ld = new RampFunctionRToR(-1, 1, F, F);
		for (int i = 0; i < mesh.countEdges(); i++) {
			Load el = new DistributedLoad(mesh.getEdge(i), ld, null);
			m.addLoad(el);
		}

		Analysis an = new LinearStaticAnalysis(m);
		an.run();

		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			Assert.assertEquals(Uh[i][0], uHatLocal[0], MathUtilities.tol6);
			Assert.assertEquals(Uh[i][1], uHatLocal[1], MathUtilities.tol6);
		}
	}

	@Test
	public void solveAndCheck3() throws SolveFailedException {
		Model m = createModel();
		Mesh mesh = m.getMesh();

		Constraint c1 = new Constraint(false, false);
		c1.setValue(0, du);
		Constraint c2 = new Constraint(false, true);
		c2.setValue(0, du);

		mesh.setConstraint(c2, MeshUtilities.seekNodesOnSurface(mesh, 1, 0, -1));
		MeshUtilities.seekNode(mesh, 1, 0).setConstraint(c1);

		Analysis an = new LinearStaticAnalysis(m);
		an.run();

		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			Assert.assertEquals(Uh[i][0], uHatLocal[0], MathUtilities.tol6);
			Assert.assertEquals(Uh[i][1], uHatLocal[1], MathUtilities.tol6);
		}
	}

	public Mesh createMeshQ4() {
		return new PatchTestQ4(0).createMesh();
	}

	public Mesh createMeshT3() {
		return new PatchTestT3(0).createMesh();
	}
}
